/*
 * Copyright (C) 2018 The Asiainfo-Ability Authors
 *
 *      Licensed under the Apache License, Version 2.0 (the "License");
 *      you may not use this file except in compliance with the License.
 *      You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 *      Unless required by applicable law or agreed to in writing, software
 *      distributed under the License is distributed on an "AS IS" BASIS,
 *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *      See the License for the specific language governing permissions and
 *      limitations under the License.
 */

package org.asiainfo.ability.gateway.custom;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.asiainfo.ability.gateway.model.Ability;
import org.asiainfo.ability.gateway.service.support.AbilityService;


import org.springframework.cloud.netflix.zuul.filters.RefreshableRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
 *  Customize the SimpleRouteLocator for dynamic setting route
 * @Author: visen
 * @Date: 2018/1/16
 * @Description:
 *
 */
public class CustomRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

    public final static Logger logger = LogManager.getLogger(CustomRouteLocator.class);

    private AbilityService abilityService;

    private ZuulProperties properties;

    public void setAbilityService(AbilityService abilityService){
        this.abilityService = abilityService;
    }

    public CustomRouteLocator(String servletPath, ZuulProperties properties) {
        super(servletPath, properties);
        this.properties = properties;
        logger.info("servletPath:{}",servletPath);
    }
    @Override
    public void refresh() {
        doRefresh();
    }

    @Override
    protected Map<String, ZuulRoute> locateRoutes() {
        LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<String, ZuulRoute>();
        //从application.properties中加载路由信息
        routesMap.putAll(super.locateRoutes());
        //从db中加载路由信息
        routesMap.putAll(loadRoutes());
        //优化一下配置
        LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>();
        for (Map.Entry<String, ZuulRoute> entry : routesMap.entrySet()) {
            String path = entry.getKey();
            // Prepend with slash if not already present.
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
            if (org.springframework.util.StringUtils.hasText(this.properties.getPrefix())) {
                path = this.properties.getPrefix() + path;
                if (!path.startsWith("/")) {
                    path = "/" + path;
                }
            }
            values.put(path, entry.getValue());
        }
        return values;
    }

    private Map<String, ZuulRoute> loadRoutes(){
        Map<String, ZuulRoute> routes = new LinkedHashMap<>();

        List<Ability> runtimeInfos = abilityService.listAbilityRuntimeInfos();
        String baseUrl = abilityService.getBaseUrl();
        for(Ability runtimeInfo:runtimeInfos) {
            ZuulRoute zuulRoute = new ZuulRoute();
            zuulRoute.setId(runtimeInfo.getName());
            zuulRoute.setPath(baseUrl+runtimeInfo.getName());
            if(runtimeInfo.getServiceType() == 0) {
                zuulRoute.setServiceId(runtimeInfo.getServiceName());
                zuulRoute.setStripPrefix(false);
            } else {
                zuulRoute.setUrl(runtimeInfo.getServiceName());
                zuulRoute.setStripPrefix(true);
            }

            routes.put(zuulRoute.getPath(),zuulRoute);
        }


        return routes;
    }

    @Override
    protected Route getRoute(ZuulRoute route, String path) {
        if (route == null) {
            return null;
        }

        String targetPath = path;
        String prefix = this.properties.getPrefix();
        if (path.startsWith(prefix) && this.properties.isStripPrefix()) {
            targetPath = path.substring(prefix.length());
        }
        if (route.isStripPrefix()) {
            int index = route.getPath().indexOf("*") - 1;
            if(index < 0) {
                String baseUrl = abilityService.getBaseUrl();
                index = route.getPath().indexOf(baseUrl)+baseUrl.length();
            }
            if (index > 0) {
                String routePrefix = route.getPath().substring(0, index);
                targetPath = "/"+targetPath.replaceFirst(routePrefix, "");
                prefix = prefix + routePrefix;
            }
        }
        Boolean retryable = this.properties.getRetryable();
        if (route.getRetryable() != null) {
            retryable = route.getRetryable();
        }
        return new Route(route.getId(), targetPath, route.getLocation(), prefix,
                retryable,
                route.isCustomSensitiveHeaders() ? route.getSensitiveHeaders() : null,
                route.isStripPrefix());
    }
}